package me.spring.cloud.common.components.auth.client;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.spring.cloud.common.components.auth.common.WebSignUtil;
import me.spring.cloud.common.components.rpc.request.CommonRequest;
import me.spring.cloud.common.components.rpc.request.header.CommonReqHeader;
import me.spring.cloud.common.components.util.json.JsonUtil;
import me.spring.cloud.common.components.web.wrapper.RepeatableReadRequestWrapper;

/**
 * 签名认证过滤器
 * @date 2018/8/15
 */
@Slf4j
@NoArgsConstructor
@AllArgsConstructor
public class AuthFilter implements Filter {

  private String secret;

  /**
   * 解析 RepeatableReadWrapper 封装的body
   * @param req
   * @Return
   */
  private static CommonRequest parseWrapperBody(ServletRequest req) {
    CommonRequest obj = null;
    try {
      if (req instanceof RepeatableReadRequestWrapper) {
        String requestBody = ((RepeatableReadRequestWrapper) req).getBody();
        obj = JsonUtil.parseObject(requestBody, CommonRequest.class);
      }
    } catch (Throwable e) {
      log.error("fail to parse body", e);
    }
    return obj;
  }

  @Override
  public void init(FilterConfig filterConfig) throws ServletException {
    // do nothing
  }

  @Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
      throws IOException, ServletException {
    CommonRequest commonRequest = parseWrapperBody(request);
    CommonReqHeader header = (CommonReqHeader) commonRequest.getHeader();
    String signCalculated = WebSignUtil.sign(commonRequest, this.secret);
    if (!signCalculated.equals(header.getSign())) {
      response.getWriter().write("请提供有效签名");
    } else {
      filterChain.doFilter(request, response);
    }
  }

  @Override
  public void destroy() {
    // do nothing
  }
}
